package com.qzboot.backend.web.module.sys.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.qzboot.backend.web.common.Ip2Region;
import com.qzboot.backend.web.common.WebUtil;
import com.qzboot.backend.web.common.config.SysLog;
import com.qzboot.backend.web.module.sys.BaseSysController;
import com.qzboot.backend.web.vo.SysChangePasswordForm;
import com.qzboot.backend.web.vo.SysLoginForm;
import com.qzboot.common.constant.SysConst;
import com.qzboot.common.support.WebResult;
import com.qzboot.common.util.PasswordUtil;
import com.qzboot.facade.entity.SysMenu;
import com.qzboot.facade.entity.SysUser;
import com.qzboot.facade.entity.SysUserToken;
import com.qzboot.facade.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zengzhihong
 * @date 2019-12-16
 */
@Slf4j
@RestController
@RequestMapping("/sys")
public class SysController extends BaseSysController {

    @Reference
    private SysUserService sysUserService;
    @Reference
    private SysUserTokenService sysUserTokenService;
    @Reference
    private SysUserRoleService sysUserRoleService;
    @Reference
    private SysAuthenticationService sysAuthenticationService;
    @Reference
    private SysMenuService sysMenuService;


    /**
     * 获取图形验证码
     *
     * @param response
     * @throws IOException
     */
    @GetMapping("/getCaptcha")
    public void getCaptcha(HttpServletResponse response) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(98, 40, 4, 10);
        getSession().setAttribute(SysConst.CAPTCHA_SESSION_KEY, circleCaptcha.getCode());
        ServletOutputStream outputStream = response.getOutputStream();
        circleCaptcha.write(outputStream);
        IoUtil.close(outputStream);
    }

    /**
     * 登录管理后台
     *
     * @param loginForm
     * @return
     */
    @SysLog("用户登录")
    @PostMapping("/login")
    public WebResult login(@Valid @RequestBody SysLoginForm loginForm, HttpServletRequest request) {
        String sessionCode = (String) getSession().getAttribute(SysConst.CAPTCHA_SESSION_KEY);
        if (!StrUtil.equalsIgnoreCase(loginForm.getCode(), sessionCode)) {
            getSession().removeAttribute(SysConst.CAPTCHA_SESSION_KEY);
            throw new IncorrectCredentialsException("验证码错误");
        }
        loginForm.setUsername(Base64.decodeStr(loginForm.getUsername()));
        loginForm.setPassword(Base64.decodeStr(loginForm.getPassword()));
        SysUser user = sysUserService.getByUsername(loginForm.getUsername());
        if (ObjectUtil.isNull(user) || !user.getPassword().equals(PasswordUtil.sha256(loginForm.getPassword(), user.getSalt()))) {
            throw new IncorrectCredentialsException("用户不存在或密码错误");
        }
        if (!SysConst.NORMAL.equals(user.getState())) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        String ip = WebUtil.getClientIP(request);
        SysUserToken userToken = sysUserTokenService.createToken(user.getId(), user.getUsername(), ip, Ip2Region.getRegion(ip));
        getSession().removeAttribute(SysConst.CAPTCHA_SESSION_KEY);
        return WebResult.success(userToken);
    }

    /**
     * 刷新token
     *
     * @param request
     * @return
     */
    @GetMapping("/refreshToken")
    public WebResult refreshToken(HttpServletRequest request) {
        String ip = WebUtil.getClientIP(request);
        SysUserToken userToken = sysUserTokenService.createToken(getUserId(), getUser().getUsername(), ip, Ip2Region.getRegion(ip));
        return WebResult.success(userToken);
    }

    /**
     * 获取登录用户信息
     *
     * @return
     */
    @GetMapping("/getUserInfo")
    public WebResult getUserInfo() {
        SysUser user = getUser();
        user.setRoleIdList(sysUserRoleService.listRoleIdByUserId(getUserId()));
        user.setPerms(sysAuthenticationService.listUserPerms(getUserId()));
        return WebResult.success(user);
    }

    /**
     * 用户菜单
     *
     * @return
     */
    @GetMapping("/listUserMenu")
    public WebResult listUserMenu(@RequestParam(required = false) Long parentId) {
        List<SysMenu> menuList = sysMenuService.listByUserId(getUserId(), parentId);
        // menuList.stream().filter(i -> SysConst.NORMAL.equals(i.getHideFlag())).collect(Collectors.toList())
        return WebResult.success(menuList);
    }


    @GetMapping("/listUserTopMenu")
    public WebResult listUserTopMenu(@RequestParam(required = false, defaultValue = "0") Long parentId) {
        List<SysMenu> menuList = sysMenuService.listByUserId(getUserId(), parentId);
        return WebResult.success(menuList.stream().filter(i -> SysConst.NORMAL.equals(i.getHideFlag())
                && SysConst.MenuType.CATALOG.getValue().equals(i.getMenuType())).collect(Collectors.toList()));
    }

    /**
     * 退出登录
     *
     * @return
     */
    @SysLog("退出登录")
    @GetMapping("/logout")
    public WebResult logout() {
        sysUserTokenService.removeByUserId(getUserId());
        super.getSubject().logout();
        return WebResult.success();
    }


    /**
     * 修改密码
     *
     * @param form
     * @return
     */
    @SysLog("修改密码")
    @PostMapping("/changePassword")
    public WebResult changePassword(@Valid @RequestBody SysChangePasswordForm form) {
        sysUserService.changePassword(getUserId(), form.getPassword(), form.getNewPassword());
        return WebResult.success();
    }
}
